/*
 * @(#)ButtonTag.java
 *
 * Copyright (c) 2003 DCIVision Ltd
 * All rights reserved.
 *
 * This software is the confidential and proprietary information of DCIVision
 * Ltd ("Confidential Information").  You shall not disclose such Confidential
 * Information and shall use it only in accordance with the terms of the license
 * agreement you entered into with DCIVision Ltd.
 */
package com.dcivision.framework.taglib.html;

import javax.servlet.jsp.JspException;
import javax.servlet.jsp.tagext.TryCatchFinally;

import org.apache.commons.lang.StringUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.struts.util.ResponseUtils;
import org.apache.taglibs.standard.lang.support.ExpressionEvaluatorManager;

import com.dcivision.framework.GlobalConstant;
import com.dcivision.framework.MessageResourcesFactory;
import com.dcivision.framework.SessionContainer;
import com.dcivision.framework.Utility;

/**
 * This is a HTML Tag for rendering css styled Button with support of language localized content through
 * system default resource bundle.
 *
 * <p>
 * This class extends ImgTag and can be extended futher to support different set of CSS class style button by
 * overriding the protected getter methods. Discuss with Henry when if a new extended class would be created.
 *
 * </p>
 *
 * <p>
 * Usage:
 * </p>
 * <p>
 * <code>&lt;html:standardButton label="common.label.new" link="test.jsp" onClick="alert('success')" target="_blank" disable="true" /&gt;</code>
 * <p>
 *
 * </p>
 * where link is the URL, onclick is the javascript to be invoked when the button is clicked, label is the key
 * of resource bundle for icon text. Localized language icon text would be retrieved.
 * </p>
 *
 * @author TC.tang, Henry Chan
 */
public class StandardButtonTag extends ImgTag  implements TryCatchFinally{

  private static final Log log = LogFactory.getLog(StandardButtonTag.class);

  private static final long serialVersionUID = 1L;

  private static final String BUTTON_CSS_STYLE = "but-standard";
  
  private static final String BUTTON_DISABLED_CSS_STYLE = "but-standard-disabled";

  /**
   * Tag attributes
   */
 
  private String label = null;

  private String onClick = "";

  private String link = ""; 
  
  private String target = null;

  private boolean disable = false;
  
  private boolean supportEnterKey = false;

  public void release() {
    super.release();
    onClick = "";
    link = "";
    target = null;
  }

  public int doStartTag() throws JspException {
    init();
    ResponseUtils.write(pageContext, getContent());

    return SKIP_BODY;
  }

  public int doEndTag() {
    return EVAL_PAGE;
  }

  /**
   * Generate and return the html content
   *
   * @return Html content string
   * @throws JspException
   */
  protected String getContent() throws JspException {
    StringBuffer content = new StringBuffer();
    SessionContainer sessionContainer = (SessionContainer) pageContext.getSession().getAttribute(GlobalConstant.SESSION_CONTAINER_KEY);
    boolean hasOnClick = hasOnClick();
    boolean hasLink = hasLink();
    handleDisabled();
    // start rendering
    content.append("<span class='" + getButtonMainClass() + "' id='"+this.id+"'>");
    content.append("<div class='but_left'></div>");

    if (hasOnClick) {
      if(isSupportEnterKey()){
        content.append("<a id='supportEnterKey' href=\"#\" onclick=\"" + getAdjustedOnClick() + "\" " + getOtherAttributes() + ">"); 
      }else{
        content.append("<a href=\"#\" onclick=\"" + getAdjustedOnClick() + "\" " + getOtherAttributes() + ">");
      }
    } else if (hasLink) {
      content.append("<a href=\"" + getELEvaluatedLink() + "\" " + getOtherAttributes() + ">");
    }

    content.append("<span class='text'>");
    if(!Utility.isEmpty(getLabel())){
      content.append(MessageResourcesFactory.getMessage(sessionContainer.getSessionLocale(), getLabel()));
    }else{
      content.append("<img src=\"");
      content.append(this.src());
      content.append("\">");
    }
    content.append("</span>");
    
    if (hasLink || hasOnClick) {
      content.append("</a>");
    }
    
    content.append("<div class='but_right'></div>");
    content.append("</span>");
    return content.toString();
  }
  
  /**
   * A quick fix for EIP-2877 adjusting onclick action event. 
   * This will remove the prefix "return" from and appends a suffix "return false;" to the original onclick action
   * 
   * @return The adjusted onclick action event
   * @throws JspException
   */
  private String getAdjustedOnClick() throws JspException {
    String onclick = getELEvaluatedOnClick();
    if(!Utility.isEmpty(onclick)){
      if(onclick.startsWith("return")){
        onclick = onclick.substring(6);
      }
      if(onclick.endsWith(";")){
        onclick = onclick.substring(0, onclick.length()-1);
      }
      onclick += ";return false;";
    }
    return onclick;
  }

  /**
   * Evaluate expression language in link attrubute
   *
   * @return EL evaluated link attribute in string
   * @throws JspException
   */
  private String getELEvaluatedLink() throws JspException {
    return (String) ExpressionEvaluatorManager.evaluate("link", getLink(), String.class, this, pageContext);
  }

  /**
   * Evaluate expression language in onClick attribute
   *
   * @return EL evaluated onClick value in string
   * @throws JspException
   */
  private String getELEvaluatedOnClick() throws JspException {
    return (String) ExpressionEvaluatorManager.evaluate("onClick", getOnClick(), String.class, this, pageContext);
  }

  /**
   * Get other href attributes/values pairs which would be appended to the end of href tag.
   *
   * @return string of attributes/values pairs
   */
  private String getOtherAttributes() {
    StringBuffer html = new StringBuffer();

    if (StringUtils.isNotBlank(getTarget())) {
      html.append(" target=\"");
      html.append(getTarget());
      html.append("'\"");
    }
    
    if(StringUtils.isNotBlank(getOnmouseover())){
      html.append(" onmouseover=\"");
      html.append(getOnmouseover());
      html.append("\"");
    }
    
    if(StringUtils.isNotBlank(getOnmouseout())){
      html.append(" onmouseout=\"");
      html.append(getOnmouseout());
      html.append("\"");
    }
    
    return html.toString();
  }

  /**
   * Retreive the main css style for the button set
   *
   * @return
   */
  protected String getButtonMainClass(){
    if(this.isDisable()){
      return getButtonDisabledMainClass();
    }else{
      return getButtonEnabledMainClass();
    }
  }
  protected String getButtonEnabledMainClass() {
    return BUTTON_CSS_STYLE;
  }
  
  protected String getButtonDisabledMainClass(){
    return BUTTON_DISABLED_CSS_STYLE;
  }
  protected boolean hasOnClick() {
    return StringUtils.isNotEmpty(onClick);
  }

  protected boolean hasLink() {
    return StringUtils.isNotEmpty(link);
  }
  
  protected void handleDisabled(){
   if(isDisable()){
     this.link = "#";
     this.onClick="return (false)";
   }  
  }
  
  public String getOnClick() {
    return onClick;
  }

  public void setOnClick(String onClick) {
    this.onClick = onClick;
  }

  public String getLabel() {
    return label;
  }

  public void setLabel(String value) {
    this.label = value;
  }

  public String getLink() {
    return link;
  }

  public void setLink(String link) {
    this.link = link;
  }

  public String getTarget() {
    return target;
  }

  public void setTarget(String target) {
    this.target = target;
  }

  public boolean isDisable() {
    return disable;
  }

  public void setDisable(boolean disable) {
    this.disable = disable;
  }
  
  public boolean isSupportEnterKey() {
    return supportEnterKey;
  }

  public void setSupportEnterKey(boolean supportEnterKey) {
    this.supportEnterKey = supportEnterKey;
  }

  public void doCatch(Throwable arg0) throws Throwable {
    log.error(arg0.toString(), arg0);    
  }

  public void doFinally() {
    release();    
  }

}
